#ifndef TRAITDEMO_H
#define TRAITDEMO_H

#include <string_view>
#include <algorithm>
//#include <type_traits>

void traitDemo();

template <typename T>
struct Enum {
    T val;
    std::string_view name;
    static constexpr std::string_view default_name = "";
};

template <typename T, auto N, typename = std::enable_if_t<std::is_enum_v<T>>>
constexpr std::string_view _to_string(T const t, std::array<Enum<T>, N> const& c)
{
    auto const it = std::find_if(std::cbegin(c), std::cend(c), [t](Enum<T> const& e)
                                 { return t == e.val; });
    return it == std::cend(c) ? Enum<T>::default_name : it->name;
}

// for new enum type
enum class animals {  //加class或struct 可以限定作用域，即只能用animals::cat，不能用cat。
    cat,
    dog,
    bird,
};
enum Animal {  //不加class 不限定作用域，能用cat。
    cat,
    dog,
    bird,
    };

//enum OtherAnimals {
//    cat,
//    };

constexpr auto animalsStr = std::array{
                                       Enum<animals>{animals::cat, "animals::cat"},
                                       Enum<animals>{animals::dog, "animals::dog"},
                                       Enum<animals>{animals::bird, "animals::bird"},
                                       };
constexpr auto AnimalsStr = std::array{
    Enum<Animal>{cat, "cat"},
    Enum<Animal>{dog, "dog"},
    Enum<Animal>{bird, "bird"},
                                       };

constexpr std::string_view to_string(animals const t)
{
    return _to_string(t,animalsStr);
}

template<class T, class U> struct CompileCheck { enum{ same_type = false }; };

template<class T> struct CompileCheck<T, T> { enum{ same_type = true }; };

struct Enum1 {
public:

    Enum1(animals a)
    {
        val1=a;
    }
    animals val1;
    constexpr static auto AnimalsStr = std::array{
        Enum<animals>{animals::cat, "animals::cat"},
        Enum<animals>{animals::dog, "animals::dog"},
        Enum<animals>{animals::bird, "animals::bird"},
                                           };

    std::string_view  toString()
    {
        auto const it = std::find_if(std::cbegin(AnimalsStr), std::cend(AnimalsStr),[this](Enum<animals> const& e)
                                     { return e.val==val1; });

        return it == std::cend(AnimalsStr) ? Enum<animals>::default_name : it->name;
    }
};



#endif // TRAITDEMO_H
